/*
 * NodoIndice.cpp
 *
 *  Created on: Sep 20, 2010
 *      Author: nicoabie
 */

#include "NodoIndice.h"
#include <string.h>
#include "stdio.h"
#include "stdlib.h"


NodoIndice::NodoIndice()
{
	this->altura = 0;
	this->id = 0;
	this->cantidadKeys = 0;
	this->idHijoActual= -1;
}

void NodoIndice::partir(Nodo *nodoHijo, long blockSize, char** promotedKey, int* promotedNodeID)
{
	/*
	NodoIndice* nodoInternoHijo = (NodoIndice*)nodoHijo;

	list<string>::iterator itKey = this->keys.begin();
	list<ReferenciaNodo*>::iterator itHijoId = this->referenciaAHijos.begin();

	string keyActual="";
	int hijoIdActual=0;
	int contadorTamanioNodoHijo = 0;
	int tamanioMedioNodoActual = getTamanioDatos()/2;

	while (itKey != this->keys.end()) {
		keyActual= (char*)*itKey;
		hijoIdActual = (int)*itHijoId;

		if (contadorTamanioNodoHijo > tamanioMedioNodoActual){
			nodoInternoHijo->insertarKey((char*)*itKey);  // el listado original ya esta ordenado, con mandarlo al final alcanza
			nodoInternoHijo->insertarIdHijo((int)*itHijoId);  // el listado original ya esta ordenado, con mandarlo al final alcanza
			itKey = keys.erase(itKey);
			itHijoId = this->idsNodosHijo.erase(itHijoId);
		}
		else {
			itKey++;
			itHijoId++;
		}

		contadorTamanioNodoHijo += sizeof(keyActual) + sizeof(hijoIdActual);
	}
	nodoInternoHijo->insertarIdHijo((int)*itHijoId);
	this->idsNodosHijo.erase(itHijoId);

	*promotedKey = this->getUltimaKey();
	*promotedNodeID = nodoInternoHijo->getId();
	itKey--;
	keys.erase(itKey);
	*/

}

void NodoIndice::insertarKey(string key)
{
	string* akey = new string(key);
	this->keys.push_front(akey);
}

void NodoIndice::insertarNuevaKey(string key)
{/*
	char* nuevaKey = new char();
	strcpy(nuevaKey,key.c_str());
	this->keys.push_front(nuevaKey);
	*/
}


void NodoIndice::insertarKeyOrdenada(char* key)
{/*
	//this->keys.push_back(key);
	this->keys.sort();

*/
}

void NodoIndice::insertarIdHijo(int idHijo)
{
	/*
	this->idsNodosHijo.push_back(idHijo);
	*/
}


void NodoIndice::insertarKeyHija(char* key, int idHijo)
{/*
	char* actualKey;

	list<char*>::iterator keyIterador 	= this->keys.begin();
	list<int>::iterator hijoIterador 	= this->idsNodosHijo.begin();
/*
	//se recorre la lista hasta encontrar algun menor..
	while (keyIterador != keys.end())
	{
		actualKey =  *keyIterador;
		//busca una key menor a la que va a insertar
		if (strcmp(key, actualKey))
			break;

		keyIterador++;
		hijoIterador++;
	}

	//una vez encontrado se le inserta la clave a insertar al nodo...
	keys.insert(keyIterador, key);

	//se le inserta la id del key insertado a la lista de nodosHijo
	hijoIterador++;
	this->idsNodosHijo.insert(hijoIterador, idHijo);
	*/

}

int NodoIndice::insertarRegistro(Registro* reg)
{
	return 0;
	//TODO ver cual es el tamanio maximo y ver si hubo overflow
}

long NodoIndice::getTamanioLibreIzquierdo()
{
	long pesoMinimo = ((ArbolBSharpConstantes::TAMANIO_BLOQUE+getTamanioDatosControl()) * ArbolBSharpConstantes::PESO_MINIMO);
	long libre = 0;
	int pesoHijos = 2*sizeof(int);//peso de los hijos

	while(getTamanioDatos()-libre > pesoMinimo )
		libre = libre + pesoHijos;

	if(libre ==0 )
		return 0;

	return libre - pesoHijos;
}

long NodoIndice::getTamanioLibreDerecho()
{
	//TODO cambiar calculo, por ahora misma implementacion que getTamanioLibreIzquierdo
	long pesoMinimo = ((ArbolBSharpConstantes::TAMANIO_BLOQUE+getTamanioDatosControl()) * ArbolBSharpConstantes::PESO_MINIMO);
	long libre = 0;
	int pesoHijos = 2*sizeof(int);//peso de los hijos

	while(getTamanioDatos()-libre > pesoMinimo )
		libre = libre + pesoHijos;

	if(libre ==0 )
		return 0;

	return libre - pesoHijos;
}

string NodoIndice::getPrimerKey()
{
	return *keys.front();
}

char* NodoIndice::getUltimaKey()
{
	return (char*)keys.back();
}

int NodoIndice::getIdHijoIzquierdo(Nodo *nodoHijo)
{/*
	int id = nodoHijo->getId();
	int idActual;
	int idHijoIzquierdo = NULL;
	list<int>::iterator iteradorHijos = this->idsNodosHijo.begin();
	while(iteradorHijos != this->idsNodosHijo.end()) {
		idActual = (int) *iteradorHijos;
		if(idActual == id) {
			if(iteradorHijos != this->idsNodosHijo.begin()) {
				iteradorHijos--;
				idHijoIzquierdo = *iteradorHijos;
			}
			return idHijoIzquierdo;
		}
		iteradorHijos++;
	}
	return idHijoIzquierdo;
	*/
}


int NodoIndice::getIdHijoDerecho(Nodo *nodoHijo)
{/*
	int id = nodoHijo->getId();
	int idActual;
	int idHijoDerecho = NULL;
	list<int>::iterator iteradorHijos = this->idsNodosHijo.begin();
	while(iteradorHijos != this->idsNodosHijo.end()) {
		idActual = (int) *iteradorHijos;
		if(idActual == id) {
			if(iteradorHijos != this->idsNodosHijo.begin()) {
				iteradorHijos++;
				idHijoDerecho = *iteradorHijos;
			}
			return idHijoDerecho;
		}
		iteradorHijos++;
	}
	return idHijoDerecho;
	*/
}

long NodoIndice::getTamanioDatos() {
	/*// se suma el tamaño de las claves y referencias que guarda.
	long rdo = 0;
	rdo = rdo + sizeof(int) * this->keys.size();
	rdo = rdo + sizeof(int) * this->idsNodosHijo.size();

	return rdo;
	*/
}

long NodoIndice::getTamanioOcupado()
{
	long rdo = 0;
	rdo = rdo + getTamanioDatos() + getTamanioDatosControl();

	return rdo;
}

int NodoIndice::getTamanioDatosControl(){
	int rdo = 0;
	rdo = rdo + sizeof(int); //cantidad de claves.
	rdo = rdo + sizeof(altura);
	rdo = rdo + sizeof(id);

	return  rdo;
}



list<string*> NodoIndice::getKeys() const
{
    return keys;
}

void NodoIndice::setIdsNodosHijo(list<ReferenciaNodo*> nodosHijo)
{
    this->referenciaAHijos = nodosHijo;
}

void NodoIndice::setKeys(list<string*> keys)
{
    this->keys = keys;
}

string NodoIndice::toString(){

	string stream="";

	stream += Utils::IntToString(this->id,CANTIDAD_BYTES_TAMANIOS_ATRIBUTOS_PRIVADOS_NODO);
	stream += Utils::IntToString(this->altura,CANTIDAD_BYTES_TAMANIOS_ATRIBUTOS_PRIVADOS_NODO);
	stream += Utils::IntToString(this->cantidadRegistros,CANTIDAD_BYTES_TAMANIOS_ATRIBUTOS_PRIVADOS_NODO);

	list<string*>::iterator it;

	for (it = this->keys.begin(); it != this->keys.end(); it++)
	{

		stream += Utils::IntToString(strlen(((string*)(*it))->c_str()),CANTIDAD_BYTES_TAMANIOS_ATRIBUTOS_PRIVADOS_NODO);
		stream += *((string*)(*it));
	}

	list<ReferenciaNodo*>::iterator itReferenciaHijos;
	for (itReferenciaHijos = this->referenciaAHijos.begin(); itReferenciaHijos != this->referenciaAHijos.end(); itReferenciaHijos++)
		{
			ReferenciaNodo* refHijo = (ReferenciaNodo*)*itReferenciaHijos;
			stream = refHijo->toString();
		}


}
void NodoIndice::fromString(string stream){


}

void NodoIndice::persistir(iostream* ios)
{
	/* Serialización de NodoIndice:
	 * <id><altura><contadorKey><KeyTamanio><Key>...<KeyTamanio><Key><ChildId>...<ChildId>
	 *
	 * */
	/*
	char*			key;
	int* 			childId;
	int				tamanioKey;

	this->cantidadKeys = this->keys.size();//cantidad de key dentro de keys
	list<ReferenciaNodo*>::iterator itReferenciaHijos;

	char* cAux 		= (char*) malloc(sizeof(int));

	//Se reasigna el tamanio de cAux para grabar el id
	cAux = (char*)realloc(cAux,sizeof(int));
	memcpy(cAux,(char*)&(this->id),sizeof(this->id));
	ios->write(cAux, sizeof(int));

	//Se graba la altura
	memcpy(cAux,(char*)&(this->altura),sizeof(int));
	ios->write(cAux, sizeof(int));

	//Se graba la cantidad de keys
	cAux = (char*)realloc(cAux,sizeof(int));
	memcpy(cAux,(char*)&(this->cantidadKeys),sizeof(int));
	ios->write(cAux, sizeof(int));

	//tamanioKey y Key
	list<char*>::iterator it;
	for (it = this->keys.begin(); it != this->keys.end(); it++)
	{
		key = (char*)*it;
		int tamanioKey = strlen(key);
		char* cAux = (char*) malloc(0);

		//Se reasigna el tamanio de cAux para grabar el tamanio de key
		cAux = (char*)realloc(cAux,sizeof(int));
		memcpy(cAux,(char*)&(tamanioKey),sizeof(int));

		ios->write(cAux, sizeof(int));

		//Se reasigna el tamanio de cAux para grabar la key
		cAux = (char*)realloc(cAux,tamanioKey);
		memcpy(cAux,key,tamanioKey);

		ios->write(cAux, tamanioKey);
	}


	//referencias
	for (itReferenciaHijos = this->referenciaAHijos.begin(); itReferenciaHijos != this->referenciaAHijos.end(); itReferenciaHijos++)
	{
		ReferenciaNodo* refHijo = (ReferenciaNodo*)*itReferenciaHijos;
		refHijo->persistir(ios);
	}
	*/
}

void NodoIndice::hidratar(iostream* ios)
{
	/* Se carga:
	 * 		<id><altura><contadorKey><KeyTamanio><Key>...<KeyTamanio><Key><ChildId>...<ChildId>
	 * la cantidad de childId es contadorRegistr+1
	 * */
	/*
	stringstream 	rdoStream;
	int 			contadorKey;
	int 			nodoHijoIdActual;
	int				tamanioKey;
	char* key = (char*) malloc(0);
	char* cAux = (char*) malloc(0);//se inicializa cAux

	//id
	cAux = (char*)realloc(cAux,sizeof(ios));
	ios->read(cAux, sizeof(int));

	this->id = 0;
	this->id = (cAux[3]<<24)|(cAux[2]<<16)|(cAux[1]<<8)|(cAux[0]<<0)|this->id;

	//altura
	ios->read(cAux, sizeof(int));
	this->altura = 0;
	this->altura = (cAux[3]<<24)|(cAux[2]<<16)|(cAux[1]<<8)|(cAux[0]<<0)|this->altura;

	//cantidad de keys
	ios->read(cAux, sizeof(int));
	int cantidadAux = 0;
	cantidadAux = (cAux[3]<<24)|(cAux[2]<<16)|(cAux[1]<<8)|(cAux[0]<<0)|cantidadAux;

	//keys
	for(int i=0; i<cantidadAux; i++)
	{
		char* cAux = (char*) malloc(0);
		char* auxKey = (char*) malloc(0);
		char* auxDato = (char*) malloc(0);

		//Tamanio key y key
		cAux = (char*)realloc(cAux,sizeof(int));
		ios->read(cAux, sizeof(int));
		//se obtiene el int del tamanio
		tamanioKey = 0;
		tamanioKey = (cAux[3]<<24)|(cAux[2]<<16)|(cAux[1]<<8)|(cAux[0]<<0)|tamanioKey;

		//Se lee la key como char* se pasa a string y se asigna...
		cAux = (char*)realloc(cAux,tamanioKey);
		ios->read(cAux, tamanioKey);

		key = (char*)realloc(key,tamanioKey);
		memcpy(key,cAux,tamanioKey);


		string sKey = key;
		sKey 		= sKey.substr(0,tamanioKey);

		this->insertarNuevaKey(sKey);
	}
	this->setCantidadKeys(cantidadAux);


	//referencias
	for(int i=0; i<=cantidadAux; i++)
	{
		ReferenciaNodo* referencia = new ReferenciaNodo();
		referencia->hidratar(ios);

		this->referenciaAHijos.push_front(referencia);
	}
*/
}




int NodoIndice::fixOverflow(Nodo *nodo, int offset, fstream *arc, unsigned int *cantidadNodos, fstream *freefs, unsigned int *cantidadNodosLibres)
{
	Nodo* nuevoNodo;
/*
	if(nodo->altura > 0)
		nuevoNodo = new NodoInterno();
	else
		nuevoNodo = new LeafNode();

	NodeFactory::assignNodeId(nuevoNodo, nodeCounter, freeNodeCounter, freefs);
	nuevoNodo->setLevel(node->getLevel());


	list<int>::iterator keyIterator = keys.begin();
	list<int>::iterator childIterator = childIds.begin();

	int a;
	int b;

	node->split(nuevoNodo, BLOCKSIZE, &a, &b );

	insertKeyChild(a,b);

	NodeFactory::writeNode(nuevoNodo, sizeOffset, fs);
	delete nuevoNodo;
	return EXIT_SUCCESS;
	*/
}

int NodoIndice::getCantidadKeys() const
{
    return cantidadKeys;
}

void NodoIndice::setCantidadKeys(int cantidadKeys)
{
    this->cantidadKeys = cantidadKeys;
}

NodoIndice::~NodoIndice() {
	/*//se vacian y destruyen las listas...
	keys.clear();
	idsNodosHijo.clear();
	*/
}
